import WeDisplayShaders from "./WeDisplayShaders"

const getNormal = `
    #ifdef HasCustomTexture0
      float getElevation(vec2 pos) {
        vec4 worldExtent = Weget_extent();
        vec2 lonlat = WeGetImageryLonLat(pos.xy,worldExtent);
        vec4 extent = weget_extentcustomTextureUniform0();
        vec2 ws = extent.xy;
        vec2 en = extent.zw;
        vec2 uv = (lonlat - ws) / (en - ws);
        uv.y = 1.0 - uv.y;
        return texture(u_customTextureUniform0,uv).r;
      }
    #else
      float getElevation(vec2 pos) {
        return 0.0f;
      }
    #endif

    float getBaseHeight(vec2 pos) {
      float cubeBaseHeight = Weget_cubeBaseHeight();
      float elev = getElevation(pos);
      if(elev > 0.0){
        return elev - cubeBaseHeight;
      }
      return cubeBaseHeight;
    }

    float getValue(vec2 uv)
    {
        bool isFlipY = Weget_shouldFlipY() > 0.0;
        vec2 st = uv;
        if(isFlipY)
        {
            st.y = 1.0 - st.y;
        }
        float value = WeDecodeValue(st);
        return value;
    }
    float itoh(float value,vec2 uv)
    {
        float offsetZ = Weget_offsetZ();
        float extrusionScale = Weget_extrusionScale();
        float minValue = Weget_minValue();
        float maxValue = Weget_maxValue();
        float i = (value - minValue) / (maxValue - minValue);
        float elev = getElevation(uv);
        return offsetZ + elev + i * extrusionScale;
    }
    float getHeight(vec2 uv)
    {
        float value = getValue(uv);
        return itoh(value,uv);
    }

    vec3 getWorldPosition(vec3 pos) {
        bool useRTCenter = Weget_useRTCenter() > 0.0;
        if(useRTCenter){
          float meterWidth = Weget_meterWidth();
          float meterHeight = Weget_meterHeight();
          vec2 st = pos.xy - 0.5;
          return vec3(st.x * meterWidth,st.y * meterHeight, pos.z);
        }

        vec4 worldExtent = Weget_extent();
        vec2 lonlat = WeGetImageryLonLat(pos.xy,worldExtent);
        return we_cartesian3FromRadians(vec3(lonlat,pos.z));
    }

    vec3 getNormal(float lineC,float lineR) {
        float normalFactor = Weget_normalFactor();
        float numLon = Weget_numLon();
        float numLat = Weget_numLat();
        float dx = 1.0 / (numLon);
        float dy = 1.0 / (numLat);
        vec2 uv0 = vec2((lineC + 0.0) * dx,(lineR + 0.0) * dy);
        vec2 uv1 = vec2((lineC + 1.0) * dx,(lineR + 0.0) * dy);
        vec2 uv2 = vec2((lineC + 1.0) * dx,(lineR + 1.0) * dy);
        vec3 p0 = getWorldPosition(vec3(uv0,getHeight(uv0) * normalFactor));
        vec3 p1 = getWorldPosition(vec3(uv1,getHeight(uv1) * normalFactor));
        vec3 p2 = getWorldPosition(vec3(uv2,getHeight(uv2) * normalFactor));
        return cross(p2 - p1,p0 - p1);
    }
`

const vsSource = `
${WeDisplayShaders.WeCartesian3FromRadians}
    out vec2 v_st;
    out vec3 v_positionEC;
    out vec3 v_normalEC;
    out vec3 v_lightDirectionEC;
    out float v_value;
    precision highp float;
    ${getNormal}

     void main()
     {
        float minValue = Weget_minValue();
        float maxValue = Weget_maxValue();
        float filterMin = Weget_filterMin();
        float filterMax = Weget_filterMax();

        float normalFactor = Weget_normalFactor();
        vec4 extent = Weget_extent();
        float numLon = Weget_numLon();
        float numLat = Weget_numLat();
        float numPointOfLine = Weget_numPointOfLine();
        float numVertexPerLine = Weget_numVertexPerLine();

        float position1 = float(gl_VertexID);
        float lineID = floor(position1 / numVertexPerLine);

        float lineC = mod(lineID,numLon);
        float lineR = floor(lineID / numLon);

        float vertexID = mod(position1, numVertexPerLine);
        float c = mod(vertexID,numPointOfLine);
        float r = floor(vertexID / numPointOfLine);

        float dx = 1.0 / numLon;
        float dy = 1.0 / numLat;

        vec3 position;

        vec3 normal;

        if(numPointOfLine == 1.0 || numPointOfLine == 2.0)
        {
            normal = getNormal(lineC,lineR);
            if(numPointOfLine == 1.0)
            {
              dx = 1.0 / (numLon - 1.0);
              dy = 1.0 / (numLat - 1.0);
            }

            vec2 uv = vec2((lineC + c) * dx,(lineR + r) * dy);
            float value = getValue(uv);
            float height = itoh(value,uv);

            position = getWorldPosition(vec3(uv,height));

            v_st = uv;
            v_positionEC = (czm_modelView * vec4(position,1.0)).xyz;
            v_value = value;
        }
        else
        {
            vec2 uv = vec2((lineC + c) * dx,(lineR + r) * dy);
            vec2 flat_uv = vec2(lineC * dx,lineR * dy);

            float baseHeight = getBaseHeight(flat_uv);

            float value = getValue(flat_uv);
            float height = itoh(value,flat_uv);
            float nr = r * 2.0 - 1.0;
            vec3 normal1;
            if(c < 2.0)
            {
                uv = vec2((lineC) * dx,(lineR + r) * dy);
                normal1 = vec3(-1.0,0.0,0.0);
                if(c == 0.0)
                    height = baseHeight;
            }
            else if(c < 4.0)
            {
                uv = vec2((lineC + 1.0) * dx,(lineR + r) * dy);
                normal1 = vec3(0.0,0.0,1.0);
                if(c == 2.0)
                    uv = vec2((lineC) * dx,(lineR + r) * dy);
            }
            else if(c < 6.0)
            {
                uv = vec2((lineC + 1.0) * dx,(lineR + r) * dy);
                normal1 = vec3(1.0,0.0,0.0);
                if(c == 5.0)
                    height = baseHeight;
            }
            else if(c < 8.0)
            {
                uv = vec2((lineC + c - 6.0) * dx,(lineR) * dy);
                normal1 = vec3(0.0,-1.0,0.0);
                if(r == 0.0)
                {
                    height = baseHeight;
                }
            }
            else if(c < 10.0)
            {
                uv = vec2((lineC + c - 8.0) * dx,(lineR + 1.0) * dy);
                normal1 = vec3(0.0,1.0,0.0);
                if(r == 1.0)
                {
                    height = baseHeight;
                }
            }
            normal = normal1;
            position = getWorldPosition(vec3(uv,height));
            v_st = uv;
            v_positionEC = (czm_modelView * vec4(position,1.0)).xyz;
            v_value = value;
        }

        float visible = WeIsNodata(v_value,minValue,filterMin,filterMax) ? 0.0 : 1.0;
        v_normalEC = czm_normal * normalize(normal);
        gl_Position = czm_modelViewProjection * vec4(position,1.0);
        gl_Position *= visible;
     }
`

const fsSource = `
${WeDisplayShaders.WeCartesian3FromRadians}
${WeDisplayShaders.WePhong}
    in vec2 v_st;
    in vec3 v_positionEC;
    in vec3 v_normalEC;
    in float v_value;
    ${getNormal}
    void main()
    {
      bool enableNormalMap = Weget_enableNormalMap() > 0.0;
      bool enableLight = Weget_enableLight() > 0.0;
      vec2 st = v_st;
      bool isFlipY = Weget_shouldFlipY() > 0.0;
      if(isFlipY)
      {
          st.y = 1.0 - st.y;
      }

      float alphaFactor = Weget_alphaFactor();
      float minValue = Weget_minValue();
      float maxValue = Weget_maxValue();
      float filterMin = Weget_filterMin();
      float filterMax = Weget_filterMax();

      float value = v_value;
      float i = (value - minValue) / (maxValue - minValue);
      vec4 color = texture(u_TFTexture,vec2(i,0.0));

      // color = vec4(vec3(i),i);

      vec3 normalEC = v_normalEC;

      color.a = WeIsNodata(value,minValue,filterMin,filterMax) ? 0.0 : color.a;

      if(color.a == 0.0) discard;

      if(enableLight)
      {
        color.rgb = WePhong(color.rgb,0.1,normalize(-v_positionEC), czm_lightDirectionEC,normalize(normalEC));
      }
      else
      {
        czm_materialInput materialInput;
        materialInput.normalEC = normalEC;
        materialInput.positionToEyeEC = -v_positionEC;
        czm_material material = czm_getDefaultMaterial(materialInput);
        material.diffuse = color.rgb;
        material.alpha = clamp(color.a,0.0,1.0);
        color = czm_phong(normalize(-v_positionEC.xyz), material, czm_lightDirectionEC);
      }

      if(alphaFactor > 0.0){
        color.a = pow(i,alphaFactor);
      }

      if(enableNormalMap){
        WeNormalEffect(color,st);
      }

      out_FragColor = color;
    }
`

export default { vsSource, fsSource }
